/******************************************************
*  Copyright(c) pages.ilovezxl.top
*  FileName :timer_linux.c
*  Author : rivulet.dave
*  Description : 系统定时器LINUX实现
*  Data : 2020-07-16
******************************************************/

/*********************************************************************
 * INCLUDES
 */

#include "stdrope.h"

#include "sallib.h"
#include "salagent.h"

#if (SAL_OSTMR == _ENABLE && SAL_PRODUCER == _SAL_LINUX_)

#include <unistd.h>
#include <pthread.h>
#include <errno.h>

#include "ostime.h"
#include "mem.h"
#include "ostmr.h"
#include "ostmr_linux.h"

/*********************************************************************
 *  EXTERNAL VARIABLES
 */

/*********************************************************************
 * MACROS
 */


/*********************************************************************
 * TYPES
 */

typedef enum _os_tmr_state
{
    OS_TMR_STATE_IDLE,
    OS_TMR_STATE_STANDBY,
    OS_TMR_STATE_ONCE,
    OS_TMR_STATE_PERIOD,
} OS_TMR_STATE_E;

typedef struct _os_timer_cb
{
    const char *pName;
    int32_t iState;
    int32_t iType;
    pthread_t iThreadId;
    pthread_mutex_t stLock;
    osTimerFunc_t pfTimerCallback;
    uint32_t uiPeriodms;
    // 启动周期运行的时间，即start timer后，timer callback的时间
    ostime_t ulPeriodTime;
} OSTIMER_CB_S;

/*********************************************************************
 * FUNCTIONS DECLARE
 */

static osTimerId_t osTimerNewByLinux(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr);
static const char* osTimerGetNameByLinux(osTimerId_t timer_id);
static osStatus_t  osTimerStartByLinux(osTimerId_t timer_id, uint32_t time_ms);
static osStatus_t  osTimerStopByLinux(osTimerId_t timer_id);
static uint32_t    osTimerIsRunningByLinux(osTimerId_t timer_id);
static osStatus_t  osTimerDeleteByLinux(osTimerId_t timer_id);
static void *osTimerThreadProcess(void *arg);

/*********************************************************************
 *  VARIABLES
 */

static OSTIMER_BASE_S s_stOSTimerLinuxObj;

/*********************************************************************
 * FUNCTIONS
 */

/**
 *   @Description: 获取系统定时器对象
 *   @param : NA
 *   @return: 对象地址
 */
void *osTimerLinuxObjNew(void)
{
    s_stOSTimerLinuxObj.pfOSTimerNew = osTimerNewByLinux;
    s_stOSTimerLinuxObj.pfOSTimerGetName = osTimerGetNameByLinux;
    s_stOSTimerLinuxObj.pfOSTimerStart = osTimerStartByLinux;
    s_stOSTimerLinuxObj.pfOSTimerStop = osTimerStopByLinux;
    s_stOSTimerLinuxObj.pfOSTimerIsRunning = osTimerIsRunningByLinux;
    s_stOSTimerLinuxObj.pfOSTimerDelete = osTimerDeleteByLinux;

    return &s_stOSTimerLinuxObj;
}

static osTimerId_t osTimerNewByLinux(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr)
{
    OSTIMER_CB_S *pstOSTimerCb = NULL;

    pstOSTimerCb = (OSTIMER_CB_S*)osMemAlloc(sizeof(OSTIMER_CB_S));
    if (!pstOSTimerCb)
    {
        return (osTimerId_t)NULL;
    }

    pstOSTimerCb->uiPeriodms = 0;
    pstOSTimerCb->pfTimerCallback = func;
    pstOSTimerCb->iState = OS_TMR_STATE_STANDBY;
    pstOSTimerCb->iType = type;

    // 每个定时器由单独的线程实现，回调函数里需要考虑，特别是实时性要求比较高的任务
    if (0 != pthread_create(&pstOSTimerCb->iThreadId, NULL, osTimerThreadProcess, pstOSTimerCb))
    {
        osMemFree((void **)&pstOSTimerCb);
        return (osTimerId_t)NULL;
    }

    if (0 != pthread_mutex_init(&pstOSTimerCb->stLock, NULL))
    {
        osMemFree((void **)&pstOSTimerCb);
        return (osTimerId_t)NULL;
    }

    if (attr)
    {
        pstOSTimerCb->pName = attr->name;
    }

    return (osTimerId_t)pstOSTimerCb;
}

static const char* osTimerGetNameByLinux(osTimerId_t timer_id)
{
    OSTIMER_CB_S *pstOSTimerCb = (OSTIMER_CB_S *)timer_id;

    if (!pstOSTimerCb)
    {
        return "unknow";
    }

    if (!pstOSTimerCb->pName)
    {
        return "unknow";
    }

    return pstOSTimerCb->pName;
}

static osStatus_t  osTimerStartByLinux(osTimerId_t timer_id, uint32_t time_ms)
{
    OSTIMER_CB_S *pstOSTimerCb = (OSTIMER_CB_S *)timer_id;

    if (!pstOSTimerCb || OS_TMR_STATE_STANDBY != pstOSTimerCb->iState)
    {
        return osError;
    }

    if (0 == time_ms)
    {
        return osError;
    }

    pthread_mutex_lock(&pstOSTimerCb->stLock);
    pstOSTimerCb->uiPeriodms = time_ms;
    pstOSTimerCb->ulPeriodTime = osTickGet();
    pstOSTimerCb->ulPeriodTime = pstOSTimerCb->ulPeriodTime + pstOSTimerCb->uiPeriodms * 1000;
    pstOSTimerCb->iState = OS_TMR_STATE_ONCE;
    pthread_mutex_unlock(&pstOSTimerCb->stLock);
    return osOK;
}

static osStatus_t  osTimerStopByLinux(osTimerId_t timer_id)
{
    OSTIMER_CB_S *pstOSTimerCb = (OSTIMER_CB_S *)timer_id;

    if (!pstOSTimerCb)
    {
        return osError;
    }

    pthread_mutex_lock(&pstOSTimerCb->stLock);
    pstOSTimerCb->iState = OS_TMR_STATE_STANDBY;
    pthread_mutex_unlock(&pstOSTimerCb->stLock);

    return osOK;
}

static uint32_t    osTimerIsRunningByLinux(osTimerId_t timer_id)
{
    OSTIMER_CB_S *pstOSTimerCb = (OSTIMER_CB_S *)timer_id;

    if (!pstOSTimerCb)
    {
        return 0;
    }

    if (OS_TMR_STATE_ONCE == pstOSTimerCb->iState || OS_TMR_STATE_PERIOD == pstOSTimerCb->iState)
    {
        return 1;
    }
    return 0;
}

static osStatus_t  osTimerDeleteByLinux(osTimerId_t timer_id)
{
    OSTIMER_CB_S *pstOSTimerCb = (OSTIMER_CB_S *)timer_id;

    if (!pstOSTimerCb)
    {
        return osError;
    }

    if (osTimerIsRunningByLinux(timer_id))
    {
        // 先暂停定时器，再删除线程
        osTimerStopByLinux(timer_id);
    }

    pthread_mutex_lock(&pstOSTimerCb->stLock);
    pthread_join(pstOSTimerCb->iThreadId, NULL);
    pstOSTimerCb->iState = OS_TMR_STATE_IDLE;
    pthread_mutex_unlock(&pstOSTimerCb->stLock);

    osMemFree((void **)&pstOSTimerCb);
    return osOK;
}

static void *osTimerThreadProcess(void *arg)
{
    OSTIMER_CB_S *pstOSTimerCb = (OSTIMER_CB_S *)arg;

    while (NULL != pstOSTimerCb)
    {
        switch (pstOSTimerCb->iState)
        {
            case OS_TMR_STATE_STANDBY:
            {
                osSleepus(1000);
                break;
            }

            case OS_TMR_STATE_ONCE:
            {
                ostime_t ulCurTick = 0;

                // 校验当前时间是否达到延时时间
                // 避免重新start后延时时间不准，有500us的误差
                do
                {
                    osSleepus(1000);
                    ulCurTick = osTickGet();
                } while (pstOSTimerCb->ulPeriodTime + 500 > ulCurTick);

                // 再次校验定时器状态
                if (OS_TMR_STATE_ONCE != pstOSTimerCb->iState)
                {
                    break;
                }

                // 先更新状态，以防在callback中更新状态失败
                pthread_mutex_lock(&pstOSTimerCb->stLock);
                if (osTimerPeriodic == pstOSTimerCb->iType)
                {
                    pstOSTimerCb->iState = OS_TMR_STATE_PERIOD;
                }
                else
                {
                    pstOSTimerCb->iState = OS_TMR_STATE_IDLE;
                }
                pthread_mutex_unlock(&pstOSTimerCb->stLock);

                // 调用回调函数
                pstOSTimerCb->pfTimerCallback(pstOSTimerCb);
                break;
            }

            case OS_TMR_STATE_PERIOD:
            {
                // 延时
                osSleepus(pstOSTimerCb->uiPeriodms * 1000);
                // 再次校验定时器状态
                if (OS_TMR_STATE_PERIOD == pstOSTimerCb->iState)
                {
                    // 调用回调函数
                    pstOSTimerCb->pfTimerCallback(pstOSTimerCb);
                }
                break;
            }

            // 线程结束
            case OS_TMR_STATE_IDLE:
            default:
            {
                pthread_mutex_destroy(&pstOSTimerCb->stLock);
                return NULL;
            }
        }
    }

    return NULL;
}

#endif  // SAL_TIMER == _ENABLE && SAL_PRODUCER == _SAL_LINUX_

/************************************** The End Of File **************************************/



